package cn.brian.framework.datasource;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author huangjinghua
 * @date 2020/6/4 15:47
 */
public class KylinPageHepler {
    /**
     * 得到查詢總數的sql
     */
    public static String getCountString(String querySelect) {
        querySelect = getLineSql(querySelect);
        int orderIndex = getLastOrderInsertPoint(querySelect);

        int formIndex = getAfterFormInsertPoint(querySelect);
        String select = querySelect.substring(0, formIndex);

        // 如果SELECT 中包含 DISTINCT 只能在外層包含COUNT
        if (select.toLowerCase().indexOf("select distinct") != -1 || querySelect.toLowerCase().indexOf("group by") != -1) {
            return new StringBuffer(querySelect.length()).append("select count(1) from (").append(querySelect.substring(0, orderIndex))
                    .append(" ) t").toString();
        } else {
            return new StringBuffer(querySelect.length()).append("select count(1) ").append(querySelect.substring(formIndex, orderIndex))
                    .toString();
        }
    }

    /**
     * 得到最后一個Order By的插入點位置
     *
     * @return 返回最后一個Order By插入點的位置
     */
    private static int getLastOrderInsertPoint(String querySelect) {
        int orderIndex = querySelect.toLowerCase().lastIndexOf("order by");
        if (orderIndex == -1 || !isBracketCanPartnership(querySelect.substring(orderIndex, querySelect.length()))) {
            throw new RuntimeException("Kylin SQL 分頁必須要有Order by 語句!");
        }
        return orderIndex;
    }

    /**
     * 得到分頁的SQL
     *
     * @param offset 偏移量
     * @param limit 位置
     * @return 分頁SQL
     */
    public static String getLimitString(String querySelect, int offset, int limit) {
        querySelect = getLineSql(querySelect);

        // String sql = querySelect + " limit " + offset + " ," + limit;
        String sql = querySelect + " limit " + limit + " offset " + offset;
        return sql;
    }

    /**
     * 將SQL語句變成一條語句，並且每個單詞的間隔都是1個空格
     *
     * @param sql SQL語句
     * @return 如果sql是NULL返回空，否則返回轉化后的SQL
     */
    private static String getLineSql(String sql) {
        return sql.replaceAll("[\r\n]", " ").replaceAll("\\s{2,}", " ");
    }

    /**
     * 得到SQL第一個正確的FROM的的插入點
     */
    private static int getAfterFormInsertPoint(String querySelect) {
        String regex = "\\s+FROM\\s+";
        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(querySelect);
        while (matcher.find()) {
            int fromStartIndex = matcher.start(0);
            String text = querySelect.substring(0, fromStartIndex);
            if (isBracketCanPartnership(text)) {
                return fromStartIndex;
            }
        }
        return 0;
    }

    /**
     * 判斷括號"()"是否匹配,並不會判斷排列順序是否正確
     *
     * @param text 要判斷的文本
     * @return 如果匹配返回TRUE,否則返回FALSE
     */
    private static boolean isBracketCanPartnership(String text) {
        if (text == null || (getIndexOfCount(text, '(') != getIndexOfCount(text, ')'))) {
            return false;
        }
        return true;
    }

    /**
     * 得到一個字符在另一個字符串中出現的次數
     *
     * @param text 文本
     * @param ch 字符
     */
    private static int getIndexOfCount(String text, char ch) {
        int count = 0;
        for (int i = 0; i < text.length(); i++) {
            count = (text.charAt(i) == ch) ? count + 1 : count;
        }
        return count;
    }
}
